# 先定义类
class Teacher: # 这是一个抽象的概念，比如说空调类，那么小米空调、格力空调都是真实存在的对象
    """
    class：定义类的关键字
    Teacher：是我定义的类名字，可以随便起的。但是首字母一定要大写
    """
    name = "沁创一达" # 定义类属性
    def __init__(self,name,age,sex): # self：表示的是对象本身
        """
        __init__：实例化方法，通过这个类实例化出来的对象，必须要有这些对象属性才可以
        :param name:
        :param age:
        :param sex:
        """
        self.name = name
        self.age = age
        self.sex = sex
        """
        self：表示的是对象本身
        .：的
        name：对象属性名称
        总结一句话：把传入过来的name重新赋值为self.name
        为什么这么做呢？
        只有这样，这个类里才可以找到对象属性（看后面）
        """
    def course(self): # 类方法
        # print(self) # 可以打印下，self到底是个什么东西
        # <__main__.Teacher object at 0x0000015F321B4FD0>，这个就是通过Teacher类实例化创建的对象地址值
        print(f"大家好，我叫：{self.name},今年：{self.age}岁，性别为：{self.sex}")
        # print(f"大家好，我叫：{self.name},今年：{self.age}岁，性别为：{self.sex}") ，哪个对象去调用它，就打印哪个对象的属性
        return "lalala"
    def play(self,tianqi,game):
        if tianqi == "晴天":
            return f"今天的天气很好，是：{tianqi}，可以一起出去玩：{game}"
        else:
            return f"今天的天气不好，是：{tianqi}，不适合出去玩：{game}"
    def func1(self):
        """
        没有任何的实例属性/对象属性
        :return: 2
        """
        print(f"1+1的值为：{1+1}")
        print("输出结果")
        return 2
# 创建对象
t1 = Teacher(name = "小白",age = 18,sex = "男") # 此时，t1就是根据Teacher类创建出来的真实对象
t2 = Teacher(name = "好健康",age = 98,sex = "女") # 此时，t2就是根据Teacher类创建出来的真实对象
# ====================================对象属性相关的===================================

# 可以打印实例属性一些信息：对象.属性
# print(t1.name) # 打印出来创建这个对象时，他的name值是多少
# print(t1.age) # 打印age的值是多少
# print(t1.sex) # 打印sex值是多少

# 打印t2对象的属性值
# print(t2.name) # 好健康

# 重新赋值对象属性：修改
# t1.name = "社会琳"
# print(t1.name) # 打印修改后的name值

# 可以新增对象属性：这个作用域仅在t1这个对象里才会有，其他对象并没有
# t1.play = "王者荣耀"
# print(t1.play)

# 打印t2的play：一定要遵循先定义后使用
# print(t2.play) # 这？ AttributeError: 'Teacher' object has no attribute 'play'

# 打印对象的所有属性
# print(t1.__dict__) # {"name":"小白","age":18,"sex":"男"}

# 删除对象属性
"""del t1.name
print(t1.name) # name走的是类属性的name
del t1.age
print(t1.age) """# 会报错，age不存在了：AttributeError: 'Teacher' object has no attribute 'age'
"""
优先级：
当对象属性不存在的时候，而类属性存在，则是使用类属性
如果对象属性不存在，类属性也没有，打印会报错
"""

# 如果不传入实例属性，对象就创建不成功给
# t3 = Teacher() # 会报错，没有传递name、age、sex三个实例属性参数

#==================================没有init方法的类=====================
class Person:
    name = "小龙" # 类属性

# 创建对象无需传入任何的参数
p1 = Person()
# 调用类属性
# print(p1.name) # 打印：小龙；因为对象属性没有name，所以会用到类属性
# 打印对象属性的所有内容
# print(p1.__dict__) # {}

# ============================= 调用类方法相关 ===============================
# 调用类方法，只能通过对象来去调用
# t1.course() # 调用类方法
# t2.course()

# 调用类方法，只能通过对象来去调用：有形参，有返回值的方法
# print(t1.play("晴天", "羽毛球")) # 今天的天气很好，是：晴天，可以一起出去玩：羽毛球


# ==============================类属性相关的=====================
# 打印类属性
# print(Teacher.name) # 沁创一达

# 查看调用类的属性
# print(Teacher.__dict__)  # {"name":"沁创一达"，}

# 修改类属性的值
# Teacher.name = "沁创测试开发培训"
# print(Teacher.name) # 变为修改后的类属性

# 不存在的属性或者方法会报错：AttributeError: type object 'Teacher' has no attribute 'play1'
# print(Teacher.play1)# 一定要遵循先定义后使用，不存在的就会报错

# 添加类属性
# Teacher.cname = "沁创一期"
# Teacher.address = "旭辉中心B座2901"
# print(Teacher.cname)
# print(Teacher.address)


# ======================调用类中带有self参数的方法
# print(Teacher.course()) # 这么去调用的话，就没有传递对象，所以是失败的  ypeError: course() missing 1 required positional argument: 'self'
# aaa = Teacher.func1(111) # 不推荐这么去调用。都是先实例化对象，再去调用的。这里的111就是占位self，并不是通过Teacher真实创建出来的对象
# print(aaa)
# ======================类属性和对象的关系===============================
class Teacher1:
    school = "buzaoya"
    xxx = "我是类的属性，也可能是对象的属性"
    yyy = 111
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    def course(self):
        # print(name) # 这样会报错，找不到name
        # 正确做法
        print(self.name) # 对象调用
        print(f"我是对象的属性：{self.name}，{self.age}，{self.sex}")
        return 111
# =================类和对象的属性的优先级====================
longzai = Teacher1("龙仔",18,"男")
xiaobai = Teacher1("小白",18,"男")
linlin = Teacher1("社会琳",98,"女")

# 对象属性的查找
# 重新给对象加了一个xxx对象属性
# longzai.xxx = "我是对象的属性"
# print(longzai.xxx)
"""
优先级：
【大前提：如果实例对象属性和类属性有重复的】
实例对象属性  > 类属性
先去找实例对象本身的有没有
没有
再去找类属性的值
"""

# ==============================类和对象的属性共享关系============
# 类属性：对象可以调用，类也可以直接调用的
# print(xiaobai.xxx) # xxx = "我是类的属性，也可能是对象的属性"
# print(Teacher1.xxx) #  xxx = "我是类的属性，也可能是对象的属性"

# 调用course方法，只能是类对象/实例对象 去调用
# print(xiaobai.course())
# print(linlin.course())

# ===================类的属性变化对类和对象的影响 =============
#  改类的属性 ctrl+鼠标左击，可以快速跳到定义它的位置
Teacher1.yyy = 333
# 对象改类的属性，改不了的
longzai.yyy = 666 # 这样相当于给对象加了一个实例属性
# print(longzai.yyy) # 666
# print(longzai.__dict__) # 你去查一下，就会发现多了一个实例属性
# {"name":"龙仔","age":18,"sex":"男","yyy":666}

# 再次打印，还会是之前修改的333，而不是666
# print(Teacher1.yyy) # 333
# ===============对象调用类中带self参数的方法===========
# 对象调用类的方法 不需要传入参数
# longzai.course()

# 类去调用，必须要传入参数，那么这个参数就是self对象
# Teacher1.course(longzai) # 这个时候，self就有实参了，就是longzai

# 直接打印对象，会是地址值
# print(longzai) # <__main__.Teacher1 object at 0x00000204B968CCA0>

# =========================绑定方法====================================
class Teacher2:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    @classmethod  # 装饰器，类装饰方法：可以直接通过类名来去调用，无需去实例化对象
    def play(self,game):
        print(f"今天天气很好，适合出去玩：{game}")
    def info(self):
        print(f"大家好，我叫：{self.name}，今年：{self.age}岁，性别为：{self.sex}")
# ================实例化对象调用========================
xiaobai1 = Teacher2("小白",19,"男")# 创建了xiaobai对象
# xiaobai1.play("打篮球")
# ============用类直接调用类方法========================
"""
改变通过传入self对象去引用，而是直接使用类去调用
"""
# Teacher2.play("打篮球")

# =============================和非绑定方法=====================================
class Teacher3:
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex
    @staticmethod # 静态方法，非绑定方法：把它变为一个普通的函数，没有任何的其他含义
    def info(num1,num2):
        """
        不再传入self，而是变为通过类可以直接调用，类对象也可以直接调用
        把它变为普通的一个函数
        不能再使用self属性值了
        :return:
        """
        print(f"{num1} + {num2}的和为：{num1+num2}")
        return num1+num2

# ================调用=========================
# 通过类直接调用静态方法
# print(Teacher3.info(1, 2))

# 通过类实例化出来的对象引用静态方法
# xiaobai2 = Teacher3("小白",19,"男")
# print(xiaobai2.info(1, 2))

"""
1、定义类
2、类属性
3、实例属性
3、类方法
4、绑定方法和非绑定方法
"""

# ===================扩展==================
# 下面都是类来实现的
"""print(str) # 字符串
print(dict) # 字典
print(tuple) # 元组
print(list) # 列表
print(set) # 集合
print(float) # 浮点型
print(int) # 整数"""






































